﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace SPAdvancedSearch.Utility
{
    /// <summary>
    /// Defines a class for helping with serializing and deserializing objects.
    /// </summary>
    public class SerializationManager
    {

        #region Methods

        public static string DehydrateObject(object objectToSerialize)
        {
            return DehydrateObject(objectToSerialize, null);
        }

        /// <summary>
        /// Returns the string representation of a serializable object.
        /// </summary>
        /// <param name="objectToSerialze"></param>
        /// <returns></returns>
        public static string DehydrateObject(object objectToSerialize, Type[] additionalTypes)
        {
            MemoryStream stm = new MemoryStream();
            StreamReader reader = new StreamReader(stm);

            string xml = string.Empty;

            try
            {
                SerializationManager.PersistObject(objectToSerialize, stm, additionalTypes);
                stm.Position = 0;
                xml = reader.ReadToEnd();
            }
            catch (Exception e)
            {
                throw new ApplicationException(string.Format("Error returning the xml representation of {0}. -- {1}", objectToSerialize.GetType().ToString(), e.Message + ", " + e.StackTrace), e);
            }
            finally
            {
                reader.Close();
                stm.Close();
            }

            return xml;

        }

        public static object HydrateObjectFromXml(Type type, string xml)
        {
            return HydrateObjectFromXml(type, xml, null);
        }

        /// <summary>
        /// Hydrates an object from an XML string.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static object HydrateObjectFromXml(Type type, string xml, Type[] additionalTypes)
        {
            if (!string.IsNullOrEmpty(xml))
            {
                MemoryStream stm = new MemoryStream();
                StreamWriter writer = new StreamWriter(stm);

                try
                {
                    writer.AutoFlush = true;
                    writer.Write(xml);

                    return HydratePersistedObject(type, stm, additionalTypes);
                }
                catch (Exception e)
                {
                    throw new ApplicationException("The XML could not be loaded.", e);
                }
                finally
                {
                    writer.Close();
                    stm.Close();
                }
            }

            return null;

        }

        /// <summary>
        /// Hydrates a serialized object from a <see cref="MemoryStream"/>.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="stm"></param>
        /// <returns></returns>
        private static object HydratePersistedObject(Type type, MemoryStream stm, Type[] additionalTypes)
        {
            XmlSerializer xmlSerializer = null;

            if (additionalTypes == null)
            {
                xmlSerializer = new XmlSerializer(type);
            }
            else
            {
                xmlSerializer = new XmlSerializer(type, additionalTypes);
            }

            try
            {
                stm.Position = 0;
                return xmlSerializer.Deserialize(stm);
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error deserializing the object.", e);
            }

        }

        /// <summary>
        /// Serializes an object to a <see cref="MemoryStream"/>.
        /// </summary>
        /// <param name="objectToSerialze"></param>
        /// <param name="stm"></param>
        private static void PersistObject(object objectToSerialize, MemoryStream stm, Type[] additionalTypes)
        {
            XmlSerializer xmlSerializer = null;
            if (additionalTypes == null)
            {
                xmlSerializer = new XmlSerializer(objectToSerialize.GetType());
            }
            else
            {
                xmlSerializer = new XmlSerializer(objectToSerialize.GetType(), additionalTypes);
            }
            StreamWriter writer = new StreamWriter(stm);

            try
            {

                writer.AutoFlush = true;
                xmlSerializer.Serialize(writer, objectToSerialize);
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error persisting the object.", e);
            }
        }

        #endregion

    }
}
